/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2018-2021. All rights reserved.
 */

package com.baidu.process.cloud.apigateway.sdk.utils;

import com.baidu.process.cloud.apigateway.sdk.utils.EmptyStringException;
import com.baidu.process.cloud.sdk.http.HttpMethodName;
import com.baidu.process.cloud.sdk.util.HttpUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Request {
    private String key = null;
    private String secret = null;
    private String method = null;
    private String url = null;
    private String body = null;
    private String fragment = null;
    private Map<String, String> headers = new Hashtable<String, String>();
    private Map<String, List<String>> queryString = new Hashtable<String, List<String>>();
    private static final Pattern PATTERN = Pattern.compile("^(?i)(post|put|patch|delete|get|options|head)$");

    @Deprecated
    public String getRegion() {
        return "";
    }

    @Deprecated
    public String getServiceName() {
        return "";
    }

    public String getKey() {
        return key;
    }

    public String getSecrect() {
        return secret;
    }

    public HttpMethodName getMethod() {
        return HttpMethodName.valueOf(method.toUpperCase(Locale.getDefault()));
    }

    public String getBody() {
        return body;
    }

    public Map<String, String> getHeaders() {
        return headers;
    }

    @Deprecated
    public void setRegion(String region) {
    }

    @Deprecated
    public void setServiceName(String serviceName) {
    }

    public void setAppKey(String appKey) throws EmptyStringException {
        if (null == appKey || appKey.trim().isEmpty()) {
            throw new EmptyStringException("appKey can not be empty");
        }
        this.key = appKey;
    }

    // 旧接口单词拼写错误，保持兼容性不修改。
    public void setAppSecrect(String appSecret) throws EmptyStringException {
        if (null == appSecret || appSecret.trim().isEmpty()) {
            throw new EmptyStringException("appSecrect can not be empty");
        }
        this.secret = appSecret;
    }

    public void setKey(String appKey) throws EmptyStringException {
        if (null == appKey || appKey.trim().isEmpty()) {
            throw new EmptyStringException("appKey can not be empty");
        }
        this.key = appKey;
    }

    public void setSecret(String appSecret) throws EmptyStringException {
        if (null == appSecret || appSecret.trim().isEmpty()) {
            throw new EmptyStringException("appSecrect can not be empty");
        }
        this.secret = appSecret;
    }

    public void setMethod(String method) throws EmptyStringException {
        if (null == method) {
            throw new EmptyStringException("method can not be empty");
        }

        Matcher match = PATTERN.matcher(method);
        if (!match.matches()) {
            throw new EmptyStringException("unsupported method");
        }
        this.method = method;
    }

    public String getUrl() throws UnsupportedEncodingException {
        StringBuilder uri = new StringBuilder();
        uri.append(url);
        if (queryString.size() > 0) {
            uri.append("?");
            int loop = 0;
            for (Map.Entry<String, List<String>> entry : queryString.entrySet()) {
                for (String value : entry.getValue()) {
                    if (loop > 0) {
                        uri.append("&");
                    }
                    uri.append(HttpUtils.urlEncode(entry.getKey(), false));
                    uri.append("=");
                    uri.append(HttpUtils.urlEncode(value, false));
                    loop++;
                }
            }
        }
        if (this.fragment != null) {
            uri.append("#");
            uri.append(this.fragment);
        }
        return uri.toString();
    }

    public void setUrl(String urlRet) throws EmptyStringException, UnsupportedEncodingException {
        if (urlRet == null || urlRet.trim().isEmpty()) {
            throw new EmptyStringException("url can not be empty");
        }
        int i = urlRet.indexOf('#');
        if (i >= 0) {
            urlRet = urlRet.substring(0, i);
        }
        i = urlRet.indexOf('?');
        this.url = urlRet;
        if (i < 0) {
            return;
        }
        String query = urlRet.substring(i + 1, urlRet.length());
        for (String item : query.split("&")) {
            String[] spl = item.split("=", 2);
            String keyRet = spl[0];
            String value = "";
            if (spl.length > 1) {
                value = spl[1];
            }
            if (!keyRet.trim().isEmpty()) {
                keyRet = URLDecoder.decode(keyRet, "UTF-8");
                value = URLDecoder.decode(value, "UTF-8");
                addQueryStringParam(keyRet, value);
            }
        }
        urlRet = urlRet.substring(0, i);

        this.url = urlRet;
    }

    public String getPath() {
        String urlRet = this.url;
        int i = urlRet.indexOf("://");
        if (i >= 0) {
            urlRet = urlRet.substring(i + 3);
        }
        i = urlRet.indexOf('/');
        if (i >= 0) {
            return urlRet.substring(i);
        } else {
            return "/";
        }
    }

    public String getHost() {
        String urlRet = this.url;
        int i = urlRet.indexOf("://");
        if (i >= 0) {
            urlRet = urlRet.substring(i + 3);
        }
        i = urlRet.indexOf('/');
        if (i >= 0) {
            urlRet = urlRet.substring(0, i);
        }
        return urlRet;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public void addQueryStringParam(String name, String value) {
        List<String> paramList = queryString.get(name);
        if (paramList == null) {
            paramList = new ArrayList<String>();
            queryString.put(name, paramList);
        }
        paramList.add(value);
    }

    public Map<String, List<String>> getQueryStringParams() {
        return queryString;
    }

    public String getFragment() {
        return fragment;
    }

    public void setFragment(String fragment) throws EmptyStringException, UnsupportedEncodingException {
        if (fragment == null || fragment.trim().isEmpty()) {
            throw new EmptyStringException("fragment can not be empty");
        }
        this.fragment = URLEncoder.encode(fragment, "UTF-8");
    }

    public void addHeader(String name, String value) {
        if (name == null || name.trim().isEmpty()) {
            return;
        }
        this.headers.put(name, value);
    }
}
